package org.yu.team2023.flashdays;

import com.google.common.collect.ImmutableList;
import net.minecraft.Util;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.Tags;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, modid = FlashDays.MODID)
public class FDConfig {


    //BASIC
    private static ForgeConfigSpec.BooleanValue ENABLE_SHOW_DAMAGE;
    public static ForgeConfigSpec.BooleanValue ENABLE_SHOW_DAMAGE_CLIENT;
    private static ForgeConfigSpec.ConfigValue<List<? extends String>> WHITE_LIST;
    private static ForgeConfigSpec.ConfigValue<List<? extends String>> WHITE_TAG_LIST;
    private static ForgeConfigSpec.BooleanValue ENABLE_HUMAN_ANNOUNCE;
    private static final Predicate<Object> ENTITY_TYPE_PREDICATE = o -> {
        String s = String.valueOf(o);
        if (!ResourceLocation.isValidResourceLocation(s)) return false;
        ResourceLocation resourceLocation = new ResourceLocation(s);
        return ForgeRegistries.ENTITY_TYPES.containsKey(resourceLocation);
    };
    private static final Predicate<Object> ENTITY_TAG_PREDICATE = o -> {
        String s = String.valueOf(o);
        return ResourceLocation.isValidResourceLocation(s);
    };

    public static boolean shouldShowDamage(Entity entity) {
        if (SHOW_DAMAGE) return true;
        EntityType<?> type = entity.getType();
        if (ENTITY_WHITELIST.contains(type)) {
            return true;
        }
        for (TagKey<EntityType<?>> tagKey : ENTITY_TAG_WHITELIST) {
            if (type.is(tagKey))
                return true;
        }
        return false;
    }

    public static void registerConfig() {
        ForgeConfigSpec.Builder serverBuilder = new ForgeConfigSpec.Builder();
        serverBuilder.comment("Settings");
        ENABLE_SHOW_DAMAGE = serverBuilder.comment("Enable show damage numbers.").define("ShowDamage", true);
        WHITE_LIST = serverBuilder.comment("White List").defineListAllowEmpty(List.of("WhiteList"), List::of, ENTITY_TYPE_PREDICATE);
        WHITE_TAG_LIST = serverBuilder.comment("White Tag List").defineListAllowEmpty(List.of("WhiteTagList"), () -> List.of(Tags.EntityTypes.BOSSES.location().toString()), ENTITY_TAG_PREDICATE);
        ENABLE_HUMAN_ANNOUNCE = serverBuilder.comment("Enable Damage Human Announce").define("ShowAnnounce", false);
        ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, serverBuilder.build());


        DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
            ForgeConfigSpec.Builder clientBuilder = new ForgeConfigSpec.Builder();
            clientBuilder.comment("Settings");
            ENABLE_SHOW_DAMAGE_CLIENT = clientBuilder.comment("Enable show damage numbers.").define("ShowDamage", true);
            ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, clientBuilder.build());
        });


        FMLJavaModLoadingContext.get().getModEventBus().addListener(FDConfig::onConfigLoad);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(FDConfig::onConfigReload);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(FDConfig::onConfigUnload);
    }

    public static boolean SHOW_ANNOUNCE = false;
    public static boolean SHOW_DAMAGE = true;
    public static boolean SHOW_DAMAGE_CLIENT = true;
    public static List<EntityType<?>> ENTITY_WHITELIST = ImmutableList.of();
    public static List<TagKey<EntityType<?>>> ENTITY_TAG_WHITELIST = ImmutableList.of();

    private static void onConfigReload(ModConfigEvent.Reloading event) {
         syncConfig();
    }

    private static void onConfigLoad(ModConfigEvent.Loading event) {
       // syncConfig();
    }

    private static void onConfigUnload(ModConfigEvent.Unloading event) {
        SHOW_DAMAGE = false;
        SHOW_ANNOUNCE = false;
        SHOW_DAMAGE_CLIENT = false;
        ENTITY_WHITELIST = ImmutableList.of();
        ENTITY_TAG_WHITELIST = ImmutableList.of();
    }

    private static void syncConfig() {
        SHOW_DAMAGE = ENABLE_SHOW_DAMAGE.get();
        SHOW_ANNOUNCE = ENABLE_HUMAN_ANNOUNCE.get();
        if (ENABLE_SHOW_DAMAGE_CLIENT != null)
            SHOW_DAMAGE_CLIENT = ENABLE_SHOW_DAMAGE_CLIENT.get();
        ENTITY_WHITELIST = WHITE_LIST.get().stream()
                .map(ResourceLocation::new)
                .map(ForgeRegistries.ENTITY_TYPES::getValue)
                .collect(Collectors.toList());
        ENTITY_TAG_WHITELIST = WHITE_TAG_LIST.get().stream()
                .map(s -> TagKey.create(ForgeRegistries.Keys.ENTITY_TYPES, new ResourceLocation(s)))
                .toList();
    }


}
